package kit;

import exception.MibException;
import util.common.CharType;
import util.common.CharTypeChecker;

import java.util.LinkedList;
import java.util.List;

public class LetterIndexer {
    private int index = 0;
    private final char[] tchars;
    private final String txt;
    private final int length;
    List<Integer> BackUpList = new LinkedList<>();

    @Override
    public String toString() {
        if (index >= 0 && index < length)
            return "LetterIndexer{" +
                    "index=" + index +
                    ", tchars[" + index + "]='" + tchars[index] + "'" +
                    ", length=" + length +
                    '}';
        else
            return "LetterIndexer{" +
                    "index=" + index +
                    ", length=" + length +
                    '}';
    }

    public LetterIndexer(String txt) {
        this.txt = txt;
        this.tchars = txt.toCharArray();
        this.length = txt.length();
    }

    /**
     * 从当前索引开始往后获取指定类型字符的字符串
     * @param types
     * @return
     */
    public String getNext(CharType... types) {
        StringBuilder builder = new StringBuilder(20);
        while (index < this.length){
            char c = tchars[index];
            if (CharTypeChecker.check(c, types)) {
                builder.append(c);
            }else {
                break;
            }
            index++;
        } //向后遍历字符直至不符合字符类型要求

        return builder.length() == 0 ? null : builder.toString();
    }

    /**
     * 从当前索引开始往后获取指定类型字符的字符串，忽略并丢弃一开始遇到的空格
     * @param types
     * @return
     */
    public String getNextIgnoreLeftSpace(CharType ... types) {
        jumpSpaces();
        return getNext(types);
    }

    /**
     * 获取指定长度字符串
     * @param num
     * @return
     */
    public String getNext(int num) {
        if (num < 0)
            throw new IllegalArgumentException();
        StringBuilder builder = new StringBuilder(num);
        int i = 0;
        for (; index+i < length && i < num ; i++) {
            builder.append(tchars[index+i]);
        }
        index += i;
        return builder.toString();
    }

    /**
     * 获取指定长度字符串
     * @param num
     * @return
     */
    public String getNextIgnoreLeftSpace(int num) {
        jumpSpaces();
        return getNext(num);
    }

    /**
     * 获取当前索引到指定字符类型的字符串，不包括指定类型的字符
     * @param types
     * @return
     */
    public String getNextUntilSpecifiedTypes(CharType ... types) {
        if (types.length == 0)
            throw new IllegalArgumentException();
        StringBuilder builder = new StringBuilder();
        while (index < this.length) {
            char c = tchars[index++];
            if ( CharTypeChecker.check(c, types)) {
                index --;
                break;
            } else{
                builder.append(c);
            }
        } //向后遍历字符直至不符合字符类型要求
        return builder.length() == 0 ? null : builder.toString();
    }

    /**
     * 获取当前索引到指定字符类型的字符串，不包括指定类型的字符，返回的字符串不以空格开始
     * @param types
     * @return
     */
    public String  getNextUntilSpecifiedTypesIgnoreLeftSpace(CharType ... types) {
        jumpSpaces();
        return getNextUntilSpecifiedTypes(types);
    }

    /**
     * 获取当前索引到指定字符类型的字符串，包括指定类型的字符
     * 例如：当前字符串"123abc123",指定字符串是"字母"，则返回"123abc"。
     * @param types
     * @return
     */
    public String getNextUntilAndIncludeSpecifiedTypes(CharType ... types) {
        int back = index;
        if (types.length == 0)
            throw new IllegalArgumentException();
        StringBuilder builder = new StringBuilder();
        builder.append(getNextUntilSpecifiedTypes(types));
        if (index == length){ // 匹配到结尾都没有以指定字符结尾的字符串
            index = back;
        }
        builder.append(getNext(types));
        return builder.toString();
    }

    /**
     * 获取当前索引到指定字符类型的字符串，包括指定类型的字符, 忽略左边空格
     * @param types
     * @return
     */
    public String getNextUntilAndIncludeSpecifiedTypesIgnoreLeftSpace(CharType ... types) {
        int back = index;
        jumpSpaces();
        String result = getNextUntilAndIncludeSpecifiedTypes(types);
        if (result == null)
            index = back;
        return result;
    }

    /**
     * 获取当前索引到指定字符类型的字符串，包括指定类型的字符
     * 例如：当前字符串"123abc123",指定字符串是"字母"，则返回"123abc"。
     * @param endStr
     * @return
     */
    public String getNextUntilAndIncludeSpecifiedTypes(String endStr) {
        int back = index;
        StringBuilder builder = new StringBuilder();
        builder.append(getNextUntilSpecifiedTypes(endStr));
        if (index == length){ // 匹配到结尾都没有以指定字符结尾的字符串
            index = back;
            return null;
        }else{
            builder.append(getNext(endStr.length()));
            return builder.toString();
        }
    }

    /**
     * 获取当前索引到指定字符类型的字符串，包括指定类型的字符, 忽略左边空格
     * @param endStr
     * @return
     */
    public String getNextUntilAndIncludeSpecifiedTypesIgnoreLeftSpace(String endStr) {
        int back = index;
        jumpSpaces();
        String result = getNextUntilAndIncludeSpecifiedTypes(endStr);
        if (result == null)
            index = back;
        return result;
    }

    /**
     * 获取当前索引到指定字符类型的字符串，不包括指定类型的字符
     * @param endStr
     * @return
     */
    public String getNextUntilSpecifiedTypes(String endStr) {
        StringBuilder builder = new StringBuilder();
        char[] endChars = endStr.toCharArray();

        for (; index < this.length; index++) {
            if (tchars[index] == endChars[0]){
                boolean match  = true;
                for (int i = 0; i < endChars.length && match ; i++) {
                    match = tchars[index + i] == endChars[i];
                }
                if (match){
                    break ; // 匹配成功
                }
            }
            builder.append(tchars[index]);
        } //向后遍历字符直至不符合字符类型要求
        return builder.length() == 0 ? null : builder.toString();
    }

    /**
     * 获取当前索引到指定字符类型的字符串，不包括指定类型的字符，返回的字符串不以空格开始
     * @param endStr
     * @return
     */
    public String  getNextUntilSpecifiedTypesIgnoreLeftSpace(String endStr) {
        jumpSpaces();
        return getNextUntilSpecifiedTypes(endStr);
    }

    /**
     * 把当前索引压入栈
     */
    public void backupIndex() {
        BackUpList.add(0, index);
    }

    /**
     * 把当前索引压入栈
     */
    public void recoverIndex() {
        if (BackUpList.size() > 0)
        {
            index = BackUpList.get(0);
            BackUpList.remove(0);
        }
        else
        {
            throw new MibException("备份列表已没有备份索引。");
        }
    }

    /**
     * 删除最近的一次索引备份
     */
    public void deleteIndex() {
        BackUpList.remove(0);
    }

    /**
     * 把当前索引压入栈
     */
    public void clearBackUpList() {
        BackUpList.clear();
    }

    public String probeNext(CharType ... types) {
        int oldindex = index;
        String r = getNext(types);
        index = oldindex;
        return r;
    }

    public String probeNextIgnoreLeftSpace(CharType ... types) {
        int oldindex = index;
        String r = getNextIgnoreLeftSpace(types);
        index = oldindex;
        return r;
    }

    /**
     * 连续取值直到遇到空格
     * @return
     */
    public String getNextToSpace() {
        StringBuilder builder = new StringBuilder(20);
        while (index < this.length) {
            char c = tchars[index++];
            if (c != ' ') {
                builder.append(c);
            } else {
                break;
            }
        } //向后遍历字符直至不符合字符类型要求
        return builder.length() == 0 ? null : builder.toString();
    }

    /**
     * 连续取值直到遇到空格，忽略左边空格
     * @return
     */
    public String getNextToSpaceIgnoreLeftSpace() {
        jumpSpaces();
        return getNextToSpace();
    }

    /**
     * 获取下一个字符
     * @return
     */
    public char getNextChar() {
        if (index < length)
            return tchars[index++];
        else
            throw new IndexOutOfBoundsException();
    }

    /**
     * 获取下一个字符
     * @return
     */
    public char getNextCharIgnoreLeftSpace() {
        jumpSpaces();
        return getNextChar();
    }

    /**
     * 探测下一个字符，索引值不改变
     * @return
     */
    public Character probeNextChar() {
        if (tchars.length > index)
            return tchars[index];
        else
            throw new IndexOutOfBoundsException();
    }

    /**
     * 探测下一个字符，索引值不改变
     * @return
     */
    public char probeNextCharIgnoreLeftSpace() {
        int oldIndex = index;
        jumpSpaces();
        char c = probeNextChar();
        index = oldIndex;
        return c;
    }

    /**
     * 跳过当前空格
     */
    public void jumpSpaces() {
        while (tchars[index] == ' ')
        {
            index ++;
            if (index >= length){
                throw new IllegalArgumentException();
            }
        }
    } // 跳过当前空格

    public void backspace(int num){
        if (index - num < 0)
            throw new MibException("回退的位置超出了边界值");
        index -= num;
    }

    /**
     * 接下来的字符是否与指定字符串匹配
     * @param str
     * @return
     */
    public boolean isNextMatch(String str){
        if (str == null)
            throw new IllegalArgumentException();
        else if (str.length() == 0)
            return true;
        else if (index + str.length() - 1 >= length)
            return false;

        char[] chars = str.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] != tchars[i + index])
                return false;
        }
        index += chars.length;
        return true;
    }

    public boolean isNextMatchIgnoreLeftSpace(String str){
        jumpSpaces();
        return isNextMatch(str);
    }

    public void reset(){
        index = 0;
        BackUpList = new LinkedList<>();
    }

    public int getIndex() {
        return index;
    }

    public char[] getTchars() {
        return tchars;
    }

    public int getLength() {
        return length;
    }

    public String getTxt() {
        return txt;
    }
}
